package com.ttg.common.component.impl;

import com.ttg.common.component.LoginCrypto;
import com.ttg.common.config.ManageConfig;
import com.ttg.common.config.MctConfig;
import com.ttg.common.config.OrganConfig;
import com.ttg.common.dto.BasicDto;
import com.ttg.common.enums.CryptoKeyConfigTypeEnum;
import com.ttg.common.utils.*;
import com.ttg.common.utils.sm.AsymmetricKey;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.TreeMap;

/**
 * @ClassName OldCryptoUtils
 * @Description 传统加密方式
 * 非对称使用RSA
 * 对称使用 AES
 * 摘要算法为 MD5
 * @Author sss
 * @Date 2022/6/8
 * @Version 1.0
 **/
@Slf4j
@Component
public class OldLoginCryptoUtils extends LoginCrypto {

    @Autowired
    @Lazy
    private ManageConfig manageConfig;

    @Autowired
    @Lazy
    private OrganConfig organConfig;

    @Autowired
    @Lazy
    private MctConfig mctConfig;


    @Override
    public String messageDigest(String msg) {
        return BasicUtils.MD5(msg);
    }

    /**
     * AES解密 + hex2byte
     *
     * @param descyptStr 待解密字符串
     * @param key        密钥
     * @return
     * @throws Exception
     */
    @Override
    public String decrypt(String descyptStr, String key) throws Exception {
        return SecurityUtils.decrypt(descyptStr, key);
    }


    /**
     * AES加密 + byte2hex
     *
     * @param encryptStr 待加密字符串
     * @param key        密钥
     * @return
     * @throws Exception
     */
    @Override
    public String encrypt(String encryptStr, String key) throws Exception {
        return SecurityUtils.encrypt(encryptStr, key);
    }

    /**
     * RSA 私钥解密 + hex2byte
     *
     * @param descyptStr    密文 hex串
     * @param privateKeyStr 私钥
     * @return
     * @throws Exception
     */
    @Override
    public String decryptByPrivateKey(String descyptStr, String privateKeyStr) throws Exception {

        // PrivateKey privateKey = RsaUtils.getPrivateKey();
        PrivateKey privateKey = RsaUtils.ConvertPrivateKey(privateKeyStr);
        byte[] dataByte = BasicUtils.hex2byte(descyptStr);
        byte[] resultByte = RsaUtils.rsaPrivateDecrypt(dataByte, privateKey);
        return new String(resultByte, StandardCharsets.UTF_8);
    }

    /**
     * RSA 公钥加密 + byte2hex
     *
     * @param encryptStr   明文
     * @param publicKeyStr 公钥
     * @return
     * @throws Exception
     */
    @Override
    public String encryptByPublicKey(String encryptStr, String publicKeyStr) throws Exception {
        PublicKey publicKey = RsaUtils.ConvertPublicKey(publicKeyStr);
        byte[] encrypt = RsaUtils.rsaPublicEncrypt(encryptStr.getBytes(), publicKey);
        return BasicUtils.byte2hex(encrypt);
    }

    /**
     * RSA 私钥加密 + byte2hex
     *
     * @param encryptStr    明文
     * @param privateKeyStr 私钥
     * @return
     * @throws Exception
     */
    @Override
    public String encryptByPrivateKey(String encryptStr, String privateKeyStr) throws Exception {
        PrivateKey privateKey = RsaUtils.ConvertPrivateKey(privateKeyStr);
        return RsaUtils.encryptByPrivateKey(encryptStr, privateKey);
    }

    /**
     * RSA 公钥解密
     *
     * @param descyptStr   密文（hex串）
     * @param publicKeyStr 公钥
     * @return
     * @throws Exception
     */
    @Override
    public String decryptByPublicKey(String descyptStr, String publicKeyStr) throws Exception {
        PublicKey publicKey = RsaUtils.ConvertPublicKey(publicKeyStr);
        byte[] dataByte = BasicUtils.hex2byte(descyptStr);
        byte[] resultByte = RsaUtils.rsaPublicDecrypt(dataByte, publicKey);
        return new String(resultByte, StandardCharsets.UTF_8);
    }

    /**
     * RSA 私钥签名
     *
     * @param sourceStr     待签串
     * @param privateKeyStr 私钥
     * @return
     * @throws Exception
     */
    @Override
    public String signByPrivateKey(String sourceStr, String privateKeyStr) throws Exception {
        return RsaUtils.rsaSignByPrivateKey(sourceStr, privateKeyStr);
    }

    /**
     * RSA 公钥验签
     *
     * @param signStr      签名
     * @param sourceStr    验证字段
     * @param publicKeyStr 公钥
     * @return
     * @throws Exception
     */
    @Override
    public boolean verifyByPublicKey(String signStr, String sourceStr, String publicKeyStr) throws Exception {
        PublicKey publicKey = RsaUtils.ConvertPublicKey(publicKeyStr);
        return SecurityUtils.verifySignWithRsa(signStr, sourceStr, publicKey);
    }


    /**
     * 生成AES 密钥
     *
     * @return
     */
    @Override
    public String genSymmetricKey() {
        return StringUtil.getUUID();
    }

    /**
     * 生成RSA 密钥对 BASE64格式
     *
     * @return
     * @throws NoSuchAlgorithmException
     */
    @Override
    public AsymmetricKey genAsymmetricKey() throws NoSuchAlgorithmException {
        KeyPair keyPair = RsaUtils.generateKeyPair();
        AsymmetricKey asymmetricKey = new AsymmetricKey();
        asymmetricKey.setPublicKey(Base64Util.encodeData(keyPair.getPublic().getEncoded()));
        asymmetricKey.setPrivateKey(Base64Util.encodeData(keyPair.getPrivate().getEncoded()));

        return asymmetricKey;
    }

    @Override
    public boolean verifySign(BasicDto organBaseDto) {
        boolean signResult = false;
        try {
            TreeMap<String, String> verifyData = new TreeMap<>();
            String sign = organBaseDto.getSign();
            verifyData.put("lang", organBaseDto.getLang());
            verifyData.put("timestamp", organBaseDto.getTimestamp());
            if (StringUtils.isNotBlank(organBaseDto.getData())) {
                verifyData.put("data", organBaseDto.getData());
            }
            String sortedStr = BasicUtils.sort(verifyData);
            signResult = SecurityUtils.verifySignWithMd5(sign, sortedStr);
        } catch (Exception e) {
            log.error("验签异常", e);
        }
        return signResult;
    }

    /**
     * 获取商户云数据库配置的RSA私钥
     *
     * @return
     */
    @Override
    public String getMctPrivateKey(String privateKey, String publicKey) {
        return privateKey;
    }

    @Override
    public String getMctPublicKey(String privateKey, String publicKey) {
        return publicKey;
    }

    /**
     * 商户云 token方式访问 签名算法 ，其实就是 私钥签名
     *
     * @param sourceStr     待签字符串
     * @param privateKeyStr 私钥
     * @return
     */
    @Override
    public String mctSignByToken(String sourceStr, String privateKeyStr) throws Exception {
        PrivateKey privateKey = RsaUtils.ConvertPrivateKey(privateKeyStr);
        return RsaUtils.encryptByPrivateKey(sourceStr, privateKey);
    }


    @Override
    public String getDefaultKey(CryptoKeyConfigTypeEnum configType) {
        String key = null;
        switch (configType) {
            case ADMIN:
                key = manageConfig.getDefaultAesKey();
                break;
            case ORGAN:
                key = organConfig.getDefaultAesKey();
                break;
            case MCT:
                key = mctConfig.getDefaultAesKey();
                break;
        }
        return key;
    }

    @Override
    public String getDefaultIV(CryptoKeyConfigTypeEnum configType) {
        return null;
    }

    /**
     * 获取系统配置的密钥
     * 注意：由于SM2算法，不支持私钥加密公钥解密，所以在SM2算法下，商户云会有两对密钥。
     * 而 RSA支持，私钥加密公钥解密，所以仅需要配置一个私钥，
     * 所以这里获取商户云公钥的方法，在RSA加密情况下，获取到的是私钥，
     * 与getPrivateKey() 返回结果一样
     *
     * @param configType
     * @return
     */
    @Override
    public String getDefaultPublicKey(CryptoKeyConfigTypeEnum configType) {
        String key = null;
        switch (configType) {
            case ADMIN:
                key = null;
                break;
            case ORGAN:
                key = null;
                break;
            case MCT:
                key = mctConfig.getDefaultPrivateKey();
                break;
            case COUPON_APP:
                key = null;
                break;
        }
        return key;
    }

    @Override
    public String getDefaultPrivateKey(CryptoKeyConfigTypeEnum configType) {
        String key = null;
        switch (configType) {
            case ADMIN:
                key = null;
                break;
            case ORGAN:
                key = null;
                break;
            case MCT:
                key = mctConfig.getDefaultPrivateKey();
                break;
            case COUPON_APP:
                key = null;
                break;
        }
        return key;
    }

}
